Application.ProcessMessages - drzi se jako kliste

Otázka od: Andreas Bednarek

22. 11. 2004 20:15

Zdravim konferenci,

mam docela problem s odstranovanim posledniho Application.ProcessMessages v me
aplikaci, obracim se na vas s nadeji, ze nekdo resil to same a povedlo se ;)

Situace ja takova:

Hlavni vlakno spusti ukol (na zaklade akce uzivatele nebo aut. planovace),
ktery vyzaduje, aby se zobrazilo okno s progressbarem a tlacitkem Storno. Ja
bych potreboval vyresit to, aby se zpracovavaly pouze zpravy posilane tomuto
oknu, presneji aby slo kliknout na Storno.

Nejsem expert na WinAPI, ale pokud vim kazde okno ma nejakou tu vlastni WndProc
nebo podobne, neslo by to obejit nejak, ze bych nepouzil VCL? Ale nevim jak.

(Predelat to napr. tak aby hlavni thread byl jen pro GUI, a ktery zobrazi
modalni okno s progress a kazdou akci spoustet v threadu, ktery bud bude
updatovat obsah okna (Synchronize) nebo bude nastavovat nejakou promennou nebo
podobne prakticky nic neresi, protoze to zaprve znamena hodne uprav a za druhe
i kdyz je zobrazene modalni okno dale se zpracovavaji vsechny zpravy aplikace
napr. pri asynchroni tcpip komunikaci pomoci third-party knihoven, ktere jsem
nucen pouzivat, nebo timer, pripadne se objevi dalsi, napr. nejaka notifikace
od jineho threadu, ktery by ale v takovem pripade mel pockat, nez si hlavni
thread vyresi co potrebuje)


Prosim poradte, nemuzu prijit na ten spravny tunning.

Diky
Andreas D4Pro


Odpovedá: Andreas Bednarek

24. 11. 2004 9:20

Zdravim, to nikdo nepouzivate nejake progress okno s tlacitkem Storno? Tomu
tak verim.
Jak se to tedy dela abych nemusel volat ProcessMessages?

Diky
A.B.

----- Original Message -----
From: "Andreas Bednarek" <bednarek@digitus.cz>
To: <delphi-l@clexpert.cz>
Sent: Monday, November 22, 2004 8:15 PM
Subject: Application.ProcessMessages - drzi se jako kliste


> Zdravim konferenci,
>
> mam docela problem s odstranovanim posledniho Application.ProcessMessages
> v me aplikaci, obracim se na vas s nadeji, ze nekdo resil to same a
> povedlo se ;)
>
> Situace ja takova:
>
> Hlavni vlakno spusti ukol (na zaklade akce uzivatele nebo aut. planovace),
> ktery vyzaduje, aby se zobrazilo okno s progressbarem a tlacitkem Storno.
> Ja bych potreboval vyresit to, aby se zpracovavaly pouze zpravy posilane
> tomuto oknu, presneji aby slo kliknout na Storno.
>
> Nejsem expert na WinAPI, ale pokud vim kazde okno ma nejakou tu vlastni
> WndProc nebo podobne, neslo by to obejit nejak, ze bych nepouzil VCL? Ale
> nevim jak.
>
> (Predelat to napr. tak aby hlavni thread byl jen pro GUI, a ktery zobrazi
> modalni okno s progress a kazdou akci spoustet v threadu, ktery bud bude
> updatovat obsah okna (Synchronize) nebo bude nastavovat nejakou promennou
> nebo podobne prakticky nic neresi, protoze to zaprve znamena hodne uprav a
> za druhe i kdyz je zobrazene modalni okno dale se zpracovavaji vsechny
> zpravy aplikace napr. pri asynchroni tcpip komunikaci pomoci third-party
> knihoven, ktere jsem nucen pouzivat, nebo timer, pripadne se objevi dalsi,
> napr. nejaka notifikace od jineho threadu, ktery by ale v takovem pripade
> mel pockat, nez si hlavni thread vyresi co potrebuje)
>
>
> Prosim poradte, nemuzu prijit na ten spravny tunning.
>
> Diky
> Andreas D4Pro
>
>


Odpovedá: Lukas Gebauer

24. 11. 2004 9:40

> Zdravim, to nikdo nepouzivate nejake progress okno s tlacitkem Storno?
> Tomu tak verim. Jak se to tedy dela abych nemusel volat
> ProcessMessages?

Jasne ze pouzivame tlacitko 'storno', ale kdyz volame nejakou akci,
ktera dlouho trva, tak ji volame ve zvlastnim threadu. Hlavni thread
aplikace je od toho, aby obsluhoval uzivatelske rozhrani a ne proto,
aby vykonaval nejake dlouhe akce. Proto zadne processmessages
nepotrebujeme.


--
Lukas Gebauer.

E-mail: gebauerl@mlp.cz
http://www.ararat.cz/synapse/ - Ararat Synapse - TCP/IP Lib.


Odpovedá: Frantisek Bohac

24. 11. 2004 9:45

Andreas Bednarek napsal(a):

>Jak se to tedy dela abych nemusel volat ProcessMessages?
>
>
Musis spustit casove narocny ukol v samostatnem threadu (TThread) - pak
neni zpracovani v hlavnim threadu nicim zatizene a vsechny controls se
zobrazuji a reaguje na udalosti.

F.


Odpovedá: Andreas Bednarek

24. 11. 2004 11:05

>> Zdravim, to nikdo nepouzivate nejake progress okno s tlacitkem Storno?
>> Tomu tak verim. Jak se to tedy dela abych nemusel volat
>> ProcessMessages?
>
> Jasne ze pouzivame tlacitko 'storno', ale kdyz volame nejakou akci,
> ktera dlouho trva, tak ji volame ve zvlastnim threadu. Hlavni thread
> aplikace je od toho, aby obsluhoval uzivatelske rozhrani a ne proto,
> aby vykonaval nejake dlouhe akce. Proto zadne processmessages
> nepotrebujeme.
>

Ja to chapu, chtel jsem se tomu vyhnout, protoze pred lety to vzniklo jinak
a nyni to znamena hodne uprav v programu vcetne mnoha thread-safe uprav,
ktere ani nevim, jestli jsou mozne (jak si napr. stoji IBObject a
multi-threading? pokud vim musi mit kazdy thread alespon vlastni
TIB_Connection ci podobne). Navic mi tam vadi, ze i kdyz zobrazim modalni
dialog, dal se zpracovavaji vsechny zpravy aplikace, co na tom, ze uzivatel
nemuze nic stisknout, kdyz mi chodi zpravy jako WSA_ASYNCSELECT nebo
WMSG_DATARECEIVED (uzivatelska: WM_APP + const), nebo WM_TIMER, ktere muzou
(i kdyz nejspise jen teoreticky) spustit konfliktni kod (a jestli se mi v
praxi neco neosvedcilo, tak jsou to flagy typu -
'probiha nejaka akce,
pockej a neprovadej jinou akci', na to totiz clovek
musi pri dalsim
programovani porad myslet a za pul roku se v tom nevyzna ani autor, kde je
to potreba a kde ne, nehlede k tomu, ze takovy flag si muze zustat
nastaveny - mou chybou, ale kdo je dokonaly - a je to v pytli - inu a prave
takove podobne flagy tam nyni jsou jinak by to padalo kazdou chvili   ).

Je to cele blbe, uznavam, ale hodne uprav znamena hodne casu a nejspis hodne
novych chyb, nemuzu si dovolit ani jedno (neni to muj soukromy proj). Doufal
jsem, ze by to slo obejit tak, ze bych na okno s progresem nepouzil VCL,
alespon provizorne. To by mi ted opravdu pomohlo ze slamastyky, kdybych mohl
pouzit stavajici strukturu programu.

[Main thread]
InitProgress(...);
while not (done or StornoClicked) do begin
    ...
    UpdateProgress(...);
end;
CloseProgress(...);


Takze nic co?  
A.B.


Odpovedá: delphin@post.cz

24. 11. 2004 11:55

> nemuze nic stisknout, kdyz mi chodi zpravy jako WSA_ASYNCSELECT nebo
> WMSG_DATARECEIVED (uzivatelska: WM_APP + const), nebo WM_TIMER, ktere
muzou

Pokud zpravy prekazi, tak WSA_xx jde nahradit overlapped zpracovanim a
WM_timer CreateWaitableTimer. Znamena to ale zrejme velke upravy.

> [Main thread]
> InitProgress(...);
> while not (done or StornoClicked) do begin
> ...
> UpdateProgress(...);
> end;
> CloseProgress(...);
>
>
> Takze nic co?  
> A.B.

Nezkousel jsem to, ale mohlo by pomoct okopirovat ProcessMessages a
ProcessMessage a nahradit

if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then

na

if PeekMessage(Msg, Button.Handle, 0, 0, PM_REMOVE) then

mely by se tak zpracovavat jenom zpravy urcene pro Button. Je to ale
nesystemove reseni, protoze po tuto dobu bude aplikace mrtva a nebude se
prekreslovat atd ...


Odpovedá: Andreas Bednarek

24. 11. 2004 13:11

> Nezkousel jsem to, ale mohlo by pomoct okopirovat ProcessMessages a
> ProcessMessage a nahradit
>
> if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
>
> na
>
> if PeekMessage(Msg, Button.Handle, 0, 0, PM_REMOVE) then
>
> mely by se tak zpracovavat jenom zpravy urcene pro Button. Je to ale
> nesystemove reseni, protoze po tuto dobu bude aplikace mrtva a nebude se
> prekreslovat atd ...
>

Hm, to by pro tuto chvili mohlo byt docela zajimave, to me nenapadlo, podle
MSDN by to mohlo i fungovat. To ze se nebude nic prekreslovat neni uplne ono
ale to je mi jasny, na okno s progressem pouziju nejake to Refresh - to
(vetsinou) funguje, a ze bude aplikace jinak 'mrtva' to mi v tehle chvili
praveze spise vyhovuje (psst ;) no mozna by se mohly odchytavat jeste nejake
WM_QUIT hlavnimu oknu (PeekMessage(Msg, FormMain.Handle, WM_QUIT, WM_QUIT,
PM_NOREMOVE) a povazovat to za Storno...?)

Az to okno zavru, tak predpokladam, ze pripadne jine nezpracovane zpravy,
ktere budou ve fronte se korektne dealokuji a nebude to zpusobovat zadny
dalsi problem...

Vyzkousim, diky!
A.B.

P.S. slibuju, ze priste nebudu cune a budu na to myslet predem ;)


Odpovedá: Karel Rys

24. 11. 2004 13:07

Andreas Bednarek dne 24 Nov 2004 v 12:31:

> > Nezkousel jsem to, ale mohlo by pomoct okopirovat ProcessMessages a
> > ProcessMessage a nahradit
> >
> > if PeekMessage(Msg, 0, 0, 0, PM_REMOVE) then
> >
> > na
> >
> > if PeekMessage(Msg, Button.Handle, 0, 0, PM_REMOVE) then
> >
> > mely by se tak zpracovavat jenom zpravy urcene pro Button. Je to ale
> > nesystemove reseni, protoze po tuto dobu bude aplikace mrtva a
> > nebude se prekreslovat atd ...
> >
>
> Hm, to by pro tuto chvili mohlo byt docela zajimave, to me nenapadlo,
> podle MSDN by to mohlo i fungovat. To ze se nebude nic prekreslovat
> neni uplne ono ale to je mi jasny, na okno s progressem pouziju
> nejake to Refresh - to (vetsinou) funguje, a ze bude aplikace jinak
> 'mrtva' to mi v tehle chvili praveze spise vyhovuje (psst ;) no mozna
> by se mohly odchytavat jeste nejake WM_QUIT hlavnimu oknu
> (PeekMessage(Msg, FormMain.Handle, WM_QUIT, WM_QUIT, PM_NOREMOVE) a
> povazovat to za Storno...?)

Ahoj,

pouzivam toto:

function KresleniPreruseno(Handle:hwnd; var Prerusil:boolean):boolean;
 var msg:tagMsg;
 begin
 if PeekMessage(msg,Handle, WM_KEYDOWN,WM_KEYDOWN,PM_NOREMOVE) or
    PeekMessage(msg,Handle, WM_LBUTTONDOWN,WM_MOUSELAST,PM_NOREMOVE) then
begin{}
  Prerusil:=true;
  result:=true;
 end else result:=false
end;


Jen tim zjistuju behem generovani sceny, zda uzivatel dela neco zajimaveho -
zpravy zustavaji ve
fronte. Pokud k necemu dojde, prerusim akci a zpravy se pak zpracuji normalne.
Jak tu jiz nekdo
radil, melo by jit odchytavat zpravy jen pro ten button, a pouzijes-li
PM_REMOVE, bude zprava
rovnou i odstranena.

Prekreslovani by se melo dat vyresit Form.Update.

Karel Rys